package com.order.manager.controller.User;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.order.manager.Model.SenderInfo;
import com.order.manager.Model.UserInfo;
import com.order.manager.Model.other.LoginRequest;
import com.order.manager.Model.other.Options;
import com.order.manager.Model.other.RestBean;
import com.order.manager.service.AuthUserDetailService;
import com.order.manager.service.impl.OrderInfoServiceImpl;
import com.order.manager.service.impl.SenderInfoServiceImpl;
import com.order.manager.service.impl.UserInfoServiceImpl;
import com.order.manager.util.JwtUtil;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.web.bind.annotation.*;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * 用户认证与授权控制器
 * 处理用户登录、注册、信息更新及权限验证等功能
 */
@RestController
//www.4399.com
@RequestMapping("api/auth")
//只是指到了我这个大的整体
@Slf4j
public class UserLoginController {

    // 注入JWT工具类（生成和解析JSON Web Token）
    @Resource
    JwtUtil jwtUtil;

    // 注入Spring Security认证管理器（处理用户认证）
//    安装maven时候就已经把他安装下来了，不需要我们去打，自己生成的
    @Resource
    AuthenticationManager authenticationManager;

    // 注入用户详情服务（加载用户信息）
    @Resource
    AuthUserDetailService authUserDetailService;

    // 注入用户信息服务（操作用户数据）
    @Resource
    UserInfoServiceImpl userInfoService;

    // 注入密码编码器（加密和解密密码）
//    pass
    @Resource
    PasswordEncoder passwordEncoder;

    // 注入订单信息服务（用于统计订单数量）
//    我们自己有的
    @Resource
    OrderInfoServiceImpl orderInfoService;

    // 注入配送员信息服务（用于统计配送员数量）
    //    我们自己有的
    @Resource
    SenderInfoServiceImpl senderInfoService;

    /**
     * 用户登录接口
     * 接收用户名和密码，验证成功后返回JWT令牌
     * @param request 登录请求对象（包含用户名和密码）
     * @return 统一响应对象（成功时包含JWT令牌）
     */
//    登录接口api/auth/login
    @PostMapping("login")
    public RestBean doLogin(@RequestBody LoginRequest request) {
        try {
            // 1.创建用户名密码认证令牌（未认证状态） 第一步创建没有激活的令牌
            UsernamePasswordAuthenticationToken auth =
                    new UsernamePasswordAuthenticationToken(request.getUsername(), request.getPassword());

            // 调用认证管理器进行认证（触发UserDetailsService加载用户信息），查看如何给你的令牌激活
            Authentication authentication = authenticationManager.authenticate(auth);


            // 将认证成功的信息存入安全上下文（供后续权限检查使用）
            SecurityContextHolder.getContext().setAuthentication(authentication);
            // 从认证对象中获取用户详情
            UserDetails userDetails = (UserDetails) authentication.getPrincipal();
            // 查询数据库中对应的用户信息（需状态为正常）
            UserInfo userInfo = userInfoService.getOne(
                    new QueryWrapper<UserInfo>().eq("username", userDetails.getUsername()).eq("state", 1)
            );
            // 使用用户唯一标识（UUID）生成JWT令牌
            String jwtToken = jwtUtil.getToken(userInfo.getUserId());
            // 返回成功响应，包含JWT令牌

            return RestBean.success(jwtToken);
        } catch (Exception e) {log.error(e.getMessage());log.error("username or password is not correct");
            // 返回认证失败响应（状态码401）
            return RestBean.failure(401, "登录失败");
        }
    }

    /**
     * 角色验证接口 - 检查是否为学校管理员
     * @param request HTTP请求（携带JWT令牌）
     * @return 统一响应对象（包含验证结果和新令牌）
     */
    @RequestMapping("/school/check")
    public RestBean schoolCheck(HttpServletRequest request) {
        // 调用通用角色验证方法，验证是否为"school"角色
        return roleFlag(request, "school");
    }

    /**
     * 角色验证接口 - 检查是否为学生
     * @param request HTTP请求（携带JWT令牌）
     * @return 统一响应对象（包含验证结果和新令牌）
     */
    @RequestMapping("/student/check")
    public RestBean studentCheck(HttpServletRequest request) {
        // 调用通用角色验证方法，验证是否为"student"角色
        return roleFlag(request, "student");
    }

    /**
     * 角色验证接口 - 检查是否为学生配送员
     * @param request HTTP请求（携带JWT令牌）
     * @return 统一响应对象（包含验证结果和新令牌）
     */
    @RequestMapping("/student_sender/check")
    public RestBean studentSenderCheck(HttpServletRequest request) {
        // 调用通用角色验证方法，验证是否为"student_sender"角色
        return roleFlag(request, "student_sender");
    }

    /**
     * 角色验证接口 - 检查是否为商家
     * @param request HTTP请求（携带JWT令牌）
     * @return 统一响应对象（包含验证结果和新令牌）
     */
    @RequestMapping("/shop/check")
    public RestBean shopCheck(HttpServletRequest request) {
        // 调用通用角色验证方法，验证是否为"shop"角色
        return roleFlag(request, "shop");
    }

    /**
     * 复合角色验证接口 - 检查是否为学生或学生配送员
     * @param request HTTP请求（携带JWT令牌）
     * @return 统一响应对象（包含验证结果和新令牌）
     */
    @RequestMapping("/student/student_sender/check")
    public RestBean checkStudentStudentSender(HttpServletRequest request) {
        // 从JWT中解析用户唯一标识（UUID）
        String uuid = jwtUtil.getJwtUsername(request);

        // 检查用户是否被禁用（isEnable=1表示启用）
        if (userInfoService.getById(uuid).getIsEnable() != 1) {
            return RestBean.failure(403, "该用户已被禁用");
        }

        // 生成新的JWT令牌（保持会话有效性）
        String token = jwtUtil.getToken(uuid);

        // 返回验证成功响应
        return RestBean.success(token);
    }

    /**
     * 通用角色验证方法
     * 验证用户是否拥有指定角色，并返回新的JWT令牌
     * @param request HTTP请求（携带JWT令牌）
     * @param role 目标角色（如"school"、"student"）
     * @return 统一响应对象（包含验证结果和新令牌）
     */
    public RestBean roleFlag(HttpServletRequest request, String role) {
        // 从JWT中解析用户唯一标识（UUID）
        String uuid = jwtUtil.getJwtUsername(request);
        log.info(uuid);

        // 检查JWT是否有效（是否包含合法UUID）
        if (uuid.isEmpty()) {
            return RestBean.failure(403, "请重新登录");
        }

        // 查询数据库中的用户信息
        UserInfo userInfo = userInfoService.getOne(
                new QueryWrapper<UserInfo>().eq("user_id", uuid)
        );

        // 验证用户是否存在
        if (userInfo == null) {
            return RestBean.failure(403, "没有此用户");
        }

        // 验证用户角色是否匹配目标角色
        if (!userInfo.getRole().equals(role)) {
            return RestBean.failure(403, "token异常，Full auth");
        }

        // 生成新的JWT令牌（刷新会话有效期）
        String token = jwtUtil.getToken(uuid);

        // 返回验证成功响应
        return RestBean.success(token);
    }

    /**
     * 用户注册接口
     * 创建新用户并返回JWT令牌
     * @param user 用户注册信息（包含用户名、密码等）
     * @return 统一响应对象（成功时包含JWT令牌）
     */
    @PostMapping("/register")
    public RestBean doUserRegister(@RequestBody UserInfo user) {
        // 验证用户名是否为空
        if (user.getUsername() == null || user.getUsername().isEmpty()) {
            return RestBean.failure(403, "用户名不能为空");
        }

        try {
            // 验证密码是否存在
            if (user.getPassword() != null && !user.getPassword().isEmpty()) {
                // 使用密码编码器加密用户密码
                String password = passwordEncoder.encode(user.getPassword());
                // 设置加密后的密码到用户对象
                user.setPassword(password);

                // 检查用户名是否已存在
                UserInfo userInfo = userInfoService.getOne(
                        new QueryWrapper<UserInfo>().eq("username", user.getUsername())
                );

                if (userInfo == null) {
                    // 验证用户角色是否合法（仅允许预定义的角色）
                    if (!(user.getRole().equals("school") ||
                            user.getRole().equals("student") ||
                            user.getRole().equals("student_sender") ||
                            user.getRole().equals("shop"))) {
                        return RestBean.failure(403, "角色权限分配错误");
                    }

                    // 如果未提供用户姓名，使用用户名作为默认姓名
                    if (user.getName() == null || user.getName().isEmpty()) {
                        user.setName(user.getUsername());
                    }

                    // 调用服务层插入用户信息
                    authUserDetailService.insertUser(user);

                    // 使用用户唯一标识生成JWT令牌
                    String jwtToken = jwtUtil.getToken(user.getUserId());

                    // 返回注册成功响应（包含JWT令牌）
                    return RestBean.success(jwtToken);
                } else {
                    // 记录日志并返回用户名已存在的错误
                    log.info("Username:" + user.getUsername() + "is exists");
                    return RestBean.failure(403, "该用户已存在，请重新输入用户名");
                }
            } else {
                // 记录日志并返回密码不能为空的错误
                log.info("密码不能为空");
                return RestBean.failure(403, "密码不能为空");
            }
        } catch (Exception e) {
            // 记录异常信息并返回注册失败错误
            log.info(e.getMessage());
            return RestBean.failure(403, "注册失败");
        }
    }

    /**
     * 用户自主更新个人信息
     * 允许用户修改部分个人信息（非敏感字段）
     * @param userLoginInfo 更新的用户信息
     * @param httpServletRequest HTTP请求（携带JWT令牌）
     * @return 统一响应对象（包含更新结果）
     */
    @RequestMapping("update/user")
    public RestBean updateUserInfoByUserSelf(@RequestBody UserInfo userLoginInfo, HttpServletRequest httpServletRequest) {
        // 记录请求的用户信息
        log.info(userLoginInfo.toString());
        try {
            // 从JWT中解析用户唯一标识（UUID）
            String jwtUsername = jwtUtil.getJwtUsername(httpServletRequest);
            log.info(jwtUsername);

            // 查询数据库中对应的用户信息（需状态正常）
            UserInfo userInfo = userInfoService.getOne(new QueryWrapper<UserInfo>()
                            .eq("user_id", jwtUsername).eq("state", "1")
            );
            if (userInfo != null) {
                // 设置更新时间戳
                userLoginInfo.setUpdateTime(new Date());
                // 使用JWT中的UUID（防止篡改）
                userLoginInfo.setUserId(jwtUsername);
                // 保留原密码（不允许通过此接口修改密码）
                userLoginInfo.setPassword(userInfo.getPassword());
                // 保留注册时间（不可修改）
                userLoginInfo.setInputTime(userInfo.getInputTime());

                // 保留账号启用状态（不可修改）
                userLoginInfo.setIsEnable(userInfo.getIsEnable());

                // 保留账号状态（不可修改）
                userLoginInfo.setState(userInfo.getState());

                // 保留用户角色（不可修改）
                userLoginInfo.setRole(userInfo.getRole());

                // 保留用户名（不可修改）
                userLoginInfo.setUsername(userInfo.getUsername());

                // 调用服务层更新用户信息
                boolean updateById = userInfoService.updateById(userLoginInfo);

                if (updateById) {
                    // 返回更新成功响应
                    return RestBean.success(userLoginInfo);
                }

                // 返回更新失败响应
                return RestBean.failure(500, "更新失败");
            } else {
                // 返回用户不存在或已禁用的错误
                return RestBean.failure(403, "jwt uuid error | user is unEnable");
            }
        } catch (Exception e) {
            // 记录异常信息并返回更新失败错误
            log.info(e.getMessage());
            return RestBean.failure(500, "更新用户信息失败");
        }
    }

    /**
     * 忘记密码重置接口
     * 通过用户名重置密码
     * @param request 包含用户名和新密码的请求
     * @return 统一响应对象（包含重置结果和新JWT令牌）
     */
    @RequestMapping("/password/forget")
    public RestBean updateByEmail(@RequestBody LoginRequest request) {
        // 查询数据库中对应的用户信息
        UserInfo userInfo = userInfoService.getOne(
                new QueryWrapper<UserInfo>().eq("username", request.getUsername())
        );

        if (userInfo != null) {
            // 使用密码编码器加密新密码
            userInfo.setPassword(passwordEncoder.encode(request.getPassword()));

            // 设置更新时间戳
            userInfo.setUpdateTime(new Date());

            // 调用服务层更新用户信息
            boolean updated = userInfoService.updateById(userInfo);

            if (updated) {
                // 生成新的JWT令牌并返回成功响应
                return RestBean.success(jwtUtil.getToken(request.getUsername()));
            }

            // 返回更新失败响应
            return RestBean.failure(500, "更新失败");
        }

        // 返回用户不存在的错误
        return RestBean.failure(403, "没有该用户");
    }

    /**
     * 用户充值接口
     * 增加用户账户余额
     * @param money 充值金额（路径变量）
     * @param request HTTP请求（携带JWT令牌）
     * @return 统一响应对象（包含充值结果）
     */
    @RequestMapping("/add/money/{money}")
    public RestBean addUserMoney(@PathVariable Double money, HttpServletRequest request) {
        // 从JWT中解析用户唯一标识（UUID）
        String uuid = jwtUtil.getJwtUsername(request);

        // 查询数据库中对应的用户信息
        UserInfo userInfo = userInfoService.getById(uuid);

        // 计算新的账户余额（原余额 + 充值金额）
        double moneyTotal = Double.valueOf(userInfo.getMoney()) + money;

        // 设置新的余额
        userInfo.setMoney(String.valueOf(moneyTotal));

        // 调用服务层更新用户信息
        boolean updated = userInfoService.updateById(userInfo);

        if (updated) {
            // 返回充值成功响应
            return RestBean.success(userInfo);
        }

        // 返回充值失败响应
        return RestBean.failure(500, "充值失败");
    }

    /**
     * 管理员更新用户信息接口
     * 管理员可修改用户的全部信息
     * @param userLoginInfo 更新的用户信息
     * @return 统一响应对象（包含更新结果）
     */
    @RequestMapping("update/admin")
    public RestBean updateUserInfoByAdmin(@RequestBody UserInfo userLoginInfo) {
        try {
            boolean flag = false; // 标记用户是否存在

            // 获取所有用户信息（用于检查用户名唯一性）
            List<UserInfo> userLoginInfos = userInfoService.list();

            // 遍历检查用户名是否已存在
            for (UserInfo loginInfo : userLoginInfos) {
                if (loginInfo.getUsername().equals(userLoginInfo.getUsername())) {
                    return RestBean.failure(403, "用户名已存在");
                }

                // 检查用户是否存在
                if (userLoginInfo.getUserId().equals(loginInfo.getUserId())) {
                    flag = true;
                }
            }

            // 如果用户存在且更新成功
            if (flag && userInfoService.updateById(userLoginInfo)) {
                // 返回更新后的用户信息
                return RestBean.success(userInfoService.getById(userLoginInfo.getUserId()));
            }

            // 返回更新失败响应
            return RestBean.failure(500, "更新失败");
        } catch (Exception e) {
            // 记录异常信息并返回更新失败错误
            log.info(e.getMessage());
            return RestBean.failure(500, "更新用户信息失败");
        }
    }

    /**
     * 获取当前用户信息接口
     * @param request HTTP请求（携带JWT令牌）
     * @return 统一响应对象（包含用户信息）
     */
    @RequestMapping("/userinfo")
    public RestBean getUserInfo(HttpServletRequest request) {
        // 从JWT中解析用户唯一标识（UUID）
        String uuid = jwtUtil.getJwtUsername(request);

        // 检查JWT是否有效
        if (uuid.isEmpty()) {
            return RestBean.failure(500, "没有此用户");
        }

        // 查询数据库中对应的用户信息
        UserInfo info = userInfoService.getById(uuid);

        // 检查用户是否存在
        if (info == null) {
            return RestBean.failure(403, "没有此用户");
        }

        // 返回用户信息
        return RestBean.success(info);
    }

    /**
     * 修改用户名接口
     * @param username 新用户名
     * @param request HTTP请求（携带JWT令牌）
     * @return 统一响应对象（包含修改结果）
     */
    @RequestMapping("/set/username")
    public RestBean setUsername(String username, HttpServletRequest request) {
        // 从JWT中解析用户唯一标识（UUID）
        String jwtUsername = jwtUtil.getJwtUsername(request);

        // 查询数据库中对应的用户信息
        UserInfo userInfo = userInfoService.getById(jwtUsername);

        if (userInfo != null) {
            // 如果新用户名与原用户名相同，无需修改
            if (userInfo.getUsername().equals(username)) {
                return RestBean.success(username);
            }

            // 检查新用户名是否已存在且状态正常
            UserInfo info = userInfoService.getOne(
                    new QueryWrapper<UserInfo>().eq("username", username)
            );

            if (info != null && info.getState() == 1) {
                return RestBean.failure(403, "该账户名已存在,请重新命名");
            }

            // 设置新用户名
            userInfo.setUsername(username);

            // 调用服务层更新用户信息
            boolean updated = userInfoService.updateById(userInfo);

            if (updated) {
                // 返回修改成功响应
                return RestBean.success(username);
            }

            // 返回修改失败响应
            return RestBean.failure(500, "更新账号信息失败");
        }

        // 返回非法修改错误
        return RestBean.failure(403, "非法修改!");
    }

    /**
     * 获取用户列表（下拉选项格式）
     * 用于前端选择框
     * @return 统一响应对象（包含用户下拉选项列表）
     */
    @RequestMapping("/user/list")
    public RestBean userList() {
        // 查询所有状态正常的用户信息
        List<UserInfo> userLoginInfos = userInfoService.list(
                new QueryWrapper<UserInfo>().eq("state", '1')
        );

        // 创建下拉选项列表
        List<Options> options = new ArrayList<>();

        // 将用户信息转换为下拉选项格式
        for (UserInfo u : userLoginInfos) {
            // 创建选项对象（标签为用户ID，值为用户名）
            Options o = new Options(u.getUserId(), u.getUsername());
            options.add(o);
        }

        // 返回下拉选项列表
        return RestBean.success(options);
    }

    /**
     * 获取学生总数接口
     * @return 统一响应对象（包含学生数量）
     */
    @RequestMapping("/student/count")
    public RestBean studentCount() {
        // 调用服务层方法获取学生数量并返回
        return RestBean.success(userInfoService.getStudentCount());
    }

    /**
     * 获取订单总数接口
     * @return 统一响应对象（包含订单数量）
     */
    @RequestMapping("/order/count")
    public RestBean orderCount() {
        // 获取所有订单并返回数量
        return RestBean.success(orderInfoService.list().size());
    }

    /**
     * 获取已审核配送员总数接口
     * @return 统一响应对象（包含配送员数量）
     */
    @RequestMapping("/sender/count")
    public RestBean senderCount() {
        // 查询所有已审核的配送员并返回数量
        return RestBean.success(senderInfoService.count(
                new QueryWrapper<SenderInfo>().eq("is_pass", 1)
        ));
    }
}